package com.jevons.geo_edit.activity;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;

import androidx.annotation.NonNull;

import com.google.gson.JsonObject;
import com.jevons.geo_edit.R;
import com.jevons.geo_edit.constant.GisGeometryType;
import com.jevons.geo_edit.fragment.GisLayerGeometryListFragment;
import com.jevons.geo_edit.fragment.GisLayerManagerFragment;
import com.jevons.geo_edit.fragment.GisOpHistoryFragment;
import com.jevons.geo_edit.geopackage.GisMapGeoManger;
import com.jevons.geo_edit.model.GisField;
import com.jevons.geo_edit.model.GisLayer;
import com.jevons.geo_edit.model.GisLayerStyle;
import com.jevons.geo_edit.model.GisProjectData;
import com.jevons.geo_edit.view.GisMapView;
import com.jevons.geo_lib.geo_op.GeoOpSaveResult;
import com.jevons.geo_lib.geo_op.GeoSubmitResult;
import com.jevons.geo_lib.geo_op.GeometryOpListener;
import com.jevons.geo_lib.geo_op.GeometryOpManager;
import com.jevons.geo_lib.helper.GeometryHelper;
import com.jevons.geo_lib.manager.MeasureManager;
import com.jevons.geo_lib.op_history.DrawType;
import com.jevons.geo_lib.view.BaseMapView;
import com.jevons.muffin.net.exception.ResponseException;
import com.jevons.muffin.net.observer.BasicResObservable;
import com.jevons.muffin.util.UuidUtils;
import com.jevons.muffin.utilcode.ImageUtils;
import com.jevons.muffin.utilcode.StringUtils;
import com.jevons.muffin.vm.BasePresenter;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Geometry;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.MultiPoint;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.turf.TurfJoins;
import com.mapbox.turf.TurfMeasurement;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;

/**
 * Copyright 2020 JxGIS
 *
 * @file GisMapPresenter
 * @auth linaisheng
 * Created on 2023/6/7.
 * Description：
 */
public class GisMapPresenter extends BasePresenter<GisMapView, GisMapViewModel> {

    private static final String GIS_GEOMETRY_SOURCE = "gis_source_";

    private static final String GIS_GEO_POINT = "gis_point_";
    private static final String GIS_GEO_POINT_ANNOTATION = "gis_point_annotation_";

    private static final String GIS_GEO_LINE = "gis_geo_line_";
    private static final String GIS_GEO_LINE_ANNOTATION = "gis_geo_line_annotation_";

    private static final String GIS_GEO_POLYGON_FILL = "gis_polygon_fill_";
    private static final String GIS_GEO_POLYGON_OUTLINE = "gis_polygon_outline_";
    private static final String GIS_GEO_POLYGON_ANNOTATION = "gis_polygon_annotation_";

    private static final String GIS_ICON_IMAGE_NAME = "gis_icon_img_";
    private static final String GIS_POLYGON_IMAGE_NAME = "gis_polygon_img_";

    private static final String FEATURE_ID = "id";


    public static final Float[] GIS_LAYER_STYLE_LINE_TYPE_1 = new Float[]{};
    //虚线
    public static final Float[] GIS_LAYER_STYLE_LINE_TYPE_2 = new Float[]{ 2f, 2f };
    //点线
    public static final Float[] GIS_LAYER_STYLE_LINE_TYPE_3 = new Float[]{ 0.5f, 5f };
    //虚线-点线
    public static final Float[] GIS_LAYER_STYLE_LINE_TYPE_4 = new Float[]{ 5f, 2f, 0.5f, 2f };
    //虚线-点-点线
    public static final Float[] GIS_LAYER_STYLE_LINE_TYPE_5 = new Float[]{ 6f, 2f, 0f, 2f, 0.5f, 2f, 0f, 2f, 3f, 2f };


    private static final String BASE_ANNOTATION_LAYER = "satellite";

    private GeometryOpManager opManager;
    private MapboxMap mMapboxMap;
    private Style loadStyle;

    private GisMapGeoManger localGeoManger;

    private boolean isLocal;
    private String gisProjectId;
    private String openVersionId;
    private String currentOpHistoryId;

    private List<GisLayer> gisLayerList = new ArrayList<>();

    private GisLayerManagerFragment layerManagerFragment;
    private boolean isShowingLayerManager;

    private GisLayerGeometryListFragment geometryListFragment;
    private boolean isShowingGeometryList;

    private GisOpHistoryFragment historyFragment;
    private boolean isShowingLayerHistory;

    private Map<String, GeoJsonSource> layerIdToSourceMap = new HashMap<>();
    private Map<String, LinkedHashMap<String, Feature>> layerIdToFeaturesMap = new HashMap<>();
    //缓存设置为不可见的图像
    private Map<String, Set<String>> invisibleFeatureMap =new HashMap<>();

    //当前操作图层
    private GisLayer currentOpLayer;

    private boolean editLayerStyle;

    //测量工具
    private MeasureManager measureManager;

    public boolean hadEdit() {
        return StringUtils.isNotEmpty(currentOpHistoryId) || editLayerStyle;
    }


    public void initMap(BaseMapView baseMapView, MapView mapView, MapboxMap mapboxMap, Style style) {
        this.mMapboxMap = mapboxMap;
        this.loadStyle = style;

        opManager = new GeometryOpManager(baseMapView, mapView, mMapboxMap, style){

            @Override
            public Observable<Feature> queryMapFeature(LatLng latLng) {
                return Observable.create(new ObservableOnSubscribe<Feature>() {
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<Feature> emitter) throws Exception {
                        Feature realFeature = queryFeatureByMapPoint(currentOpLayer, latLng);
                        emitter.onNext(realFeature);
                        emitter.onComplete();
                    }
                });
            }

            @Override
            public Observable<Geometry> dealGeometryDifference(Geometry geometry) {
                //多边形去重
                if (currentOpLayer.getGeometryType() == GisGeometryType.Polygon) {
                    return Observable.create(new ObservableOnSubscribe<Geometry>() {
                        @Override
                        public void subscribe(@NonNull ObservableEmitter<Geometry> emitter) throws Exception {
                            //查询图形四至界限内可能相交的图像
                            double[] bbox = TurfMeasurement.bbox(geometry);
                            LatLng latLngLeftBottom = new LatLng(bbox[1], bbox[0]);
                            LatLng latLngRightTop = new LatLng(bbox[3], bbox[2]);

                            PointF pointLeftBottom = mMapboxMap.getProjection().toScreenLocation(latLngLeftBottom);
                            PointF pointRightTop = mMapboxMap.getProjection().toScreenLocation(latLngRightTop);

                            RectF rectF = new RectF(pointLeftBottom.x, pointRightTop.y, pointRightTop.x, pointLeftBottom.y);
                            String queryLayerId = getGisLayerOnMapLayerId(currentOpLayer);
                            List<Feature> features = mMapboxMap.queryRenderedFeatures(rectF, queryLayerId);
                            if (features.size() > 0) {
                                GeometryHelper geometryHelper = new GeometryHelper();

                                //去重操作
                                Geometry sourcePolygon = geometry;
                                for (Feature feature : features) {
                                    Geometry geometry = geometryHelper.difference(
                                            sourcePolygon, feature.geometry());
                                    if (geometry != null) {
                                        sourcePolygon = geometry;
                                    }
                                }
                                emitter.onNext(sourcePolygon);
                            } else {
                                emitter.onNext(geometry);
                            }
                            emitter.onComplete();
                        }
                    });

                } else {
                    return super.dealGeometryDifference(geometry);
                }
            }

            @Override
            public Observable queryCommonPointGeometry(Feature feature) {
                if (currentOpLayer.getGeometryType() == GisGeometryType.Polygon) {
                    return Observable.create(new ObservableOnSubscribe<Feature>() {
                        @Override
                        public void subscribe(@NonNull ObservableEmitter<Feature> emitter) throws Exception {
                            //查询图形四至界限内可能相交的图像
                            double[] bbox = TurfMeasurement.bbox(feature);
                            LatLng latLngLeftBottom = new LatLng(bbox[1], bbox[0]);
                            LatLng latLngRightTop = new LatLng(bbox[3], bbox[2]);

                            PointF pointLeftBottom = mMapboxMap.getProjection().toScreenLocation(latLngLeftBottom);
                            PointF pointRightTop = mMapboxMap.getProjection().toScreenLocation(latLngRightTop);

                            RectF rectF = new RectF(pointLeftBottom.x, pointRightTop.y, pointRightTop.x, pointLeftBottom.y);
                            String queryLayerId = getGisLayerOnMapLayerId(currentOpLayer);
                            List<Feature> renderedFeatures = mMapboxMap.queryRenderedFeatures(rectF, queryLayerId);

                            Map<String, Feature> resultMap = new HashMap<>();
                            if (renderedFeatures.size() > 0) {
                                String featureId = feature.getStringProperty(KEY_FEATURE_ID);

                                for (Feature renderedFeature : renderedFeatures) {
                                    String renderedFeatureId = renderedFeature.getStringProperty(KEY_FEATURE_ID);
                                    if (featureId.equals(renderedFeatureId)) {
                                        //跳过相同图形
                                        continue;
                                    }

                                    //queryRenderedFeatures查询出的图像时模糊图像，不是真实坐标
                                    Feature realFeature = layerIdToFeaturesMap
                                            .get(currentOpLayer.getId()).get(renderedFeatureId);

                                    boolean isTouche = GeometryHelper.geometryTouches(
                                            feature.geometry(), realFeature.geometry());
                                    if (isTouche) {
                                        //有公共的边界点
                                        resultMap.put(renderedFeatureId, realFeature);
                                    }
                                }
                            }

                            for (Feature item : resultMap.values()) {
                                emitter.onNext(item);
                            }

                            emitter.onComplete();
                        }
                    });
                } else {
                    return super.queryCommonPointGeometry(feature);
                }
            }

            @Override
            public boolean isAddCommonPointOnQiege() {
                return true;
            }
        };
        opManager.addGeoOperationLayer(BASE_ANNOTATION_LAYER);
        opManager.setGeometryOpListener(new GeometryOpListener() {
            @Override
            public void entryGeoEditModel(DrawType drawType) {
                getView().entryGeoEditModel(drawType);
                if (drawType == DrawType.Bianjie) {
                    opManager.setSelectedEditGeometryLayerVisible(false);
                }
                hideLayerManagerFragment();
            }

            @Override
            public void existGeoEditModel(DrawType drawType) {
                getView().existGeoEditModel(drawType);
                if (drawType == DrawType.Bianjie) {
                    opManager.setSelectedEditGeometryLayerVisible(true);
                }
            }

            @Override
            public void onCompleteStateChange(DrawType drawType, boolean isComplete) {
                getView().onOpCompleteChange(drawType, isComplete);
            }

            @Override
            public void onOpSaveResult(DrawType drawType, GeoOpSaveResult result) {
                getView().onOpSaveResult(drawType);
            }
        });


        measureManager = new MeasureManager(mapView, mapboxMap, style);
        measureManager.addMeasureLayerAbove("op_edit_point");
        try {
            localGeoManger = new GisMapGeoManger(getContext());
        } catch (Exception e) {
            e.printStackTrace();
            getView().finishWithMsg("打开离线数据失败");
        }
    }

    public void initData(String id, String versionId, boolean isLocal) {
        gisProjectId = id;
        openVersionId = versionId;
        this.isLocal = isLocal;
        gisLayerList = new ArrayList<>();

        loadMapData();
    }

    private void loadMapData() {
        if (localGeoManger != null) {
            //检查是否有操作历史
            String lastHistoryId = localGeoManger.existOpHistory(gisProjectId);
            if (StringUtils.isNotEmpty(lastHistoryId)) {
                loadOpHistoryData(lastHistoryId, true);
            } else if (StringUtils.isNotEmpty(openVersionId)) {
                if (isLocal) {
                    loadProjectVersionData(openVersionId, true);
                } else {
                    loadNetProjectVersionData(gisProjectId, true);
                }
            } else {
                loadNetProjectVersionData(gisProjectId, true);
            }
        }
    }

    private void loadNetProjectVersionData(String projectId, boolean animateCamera) {
//        mapLoader.getGisProjectData(projectId)
//                .compose(getView().bindToLifecycle())
//                .subscribe(new BasicResObservable<GisProjectData>(){
//
//                    @Override
//                    public void responseSuccess(GisProjectData response) {
//                        if (response != null && response.layers != null && response.layers.size() > 0) {
//                            loadGisProjectData(response, animateCamera);
//                        } else {
//                            animateCameraToUavMap();
//                        }
//                    }
//
//                    @Override
//                    public void responseError(ResponseException exception) {
//                        getView().showToast(exception.getDescription());
//                        exception.printStackTrace();
//                    }
//                });
    }

    private void loadProjectVersionData(String versionId, boolean animateCamera) {
//        localGeoManger.loadProjectVersionData(versionId)
//                .compose(getView().bindToLifecycle())
//                .subscribe(new BasicResObservable<GisProjectData>(){
//
//                    @Override
//                    public void responseSuccess(GisProjectData response) {
//                        if (response != null && response.layers != null && response.layers.size() > 0) {
//                            loadGisProjectData(response, animateCamera);
//                        }
//                    }
//
//                    @Override
//                    public void responseError(ResponseException exception) {
//                        getView().showToast(exception.getDescription());
//                        exception.printStackTrace();
//                    }
//                });
    }

    private void loadOpHistoryData(String historyId, boolean animateCamera) {
        localGeoManger.loadOpHistoryData(historyId)
                .compose(getView().bindToLifecycle())
                .subscribe(new BasicResObservable<GisProjectData>(){

                    @Override
                    public void responseSuccess(GisProjectData response) {
                        if (response != null && response.layers != null && response.layers.size() > 0) {
                            currentOpHistoryId = response.getHistoryId();

                            loadGisProjectData(response, animateCamera);
                        }
                    }

                    @Override
                    public void responseError(ResponseException exception) {
                        getView().showToast(exception.getDescription());
                        exception.printStackTrace();
                    }
                });
    }

    private void loadGisProjectData(
            GisProjectData response, boolean animateCamera) {
        currentOpHistoryId = response.getHistoryId();
        gisLayerList.addAll(response.layers);

        initGisGeometryLayer();

        setGisGeometrySourceData(response.layerToFeatureMap, animateCamera);

        if (layerManagerFragment != null) {
            layerManagerFragment.initData(gisLayerList);
        }
    }


    private void initGisGeometryLayer() {
        //将gisLayerList从后往前遍历，达到第一个item在最顶层效果
        String aboveLayerId = BASE_ANNOTATION_LAYER;
        for (int i = gisLayerList.size() -1; i >=0; i--) {
            GisLayer gisLayer = gisLayerList.get(i);
            aboveLayerId = addGeometryLayer(gisLayer, aboveLayerId);
        }
    }

    private String addGeometryLayer(GisLayer gisLayer, String aboveLayerId) {
        String gisLayerId = gisLayer.getId();
        String sourceId = GIS_GEOMETRY_SOURCE + gisLayerId;
        GeoJsonSource jsonSource = new GeoJsonSource(sourceId);
        loadStyle.addSource(jsonSource);
        layerIdToSourceMap.put(gisLayer.getId(), jsonSource);

        GisLayerStyle layerStyle = gisLayer.getMyLayerStyle();
        if (gisLayer.getGeometryType() == GisGeometryType.Point) {
            String iconImageName = GIS_ICON_IMAGE_NAME + gisLayer.getId();
            addIconImage(iconImageName, gisLayer);
            String layerId = getGisLayerOnMapLayerId(gisLayer);

            SymbolLayer symbolLayer = new SymbolLayer(layerId, sourceId)
                    .withProperties(
                            PropertyFactory.iconImage(iconImageName),
                            PropertyFactory.iconSize(layerStyle.getPointSize() / 20f),
                            PropertyFactory.iconOpacity(layerStyle.getFillOpacity()),
                            PropertyFactory.iconOptional(true),
                            PropertyFactory.iconIgnorePlacement(false),
                            PropertyFactory.iconAllowOverlap(true),
                            PropertyFactory.iconIgnorePlacement(true)
                    );
            loadStyle.addLayerAbove(symbolLayer, aboveLayerId);

            String layerAnnotationId = GIS_GEO_POINT_ANNOTATION + gisLayerId;
            String showAnnotationKey = layerStyle.getShowAnnotationKey();
            SymbolLayer annotationLayer = new SymbolLayer(layerAnnotationId, sourceId)
                    .withProperties(
                            PropertyFactory.textSize(layerStyle.getFontSize()),
                            PropertyFactory.textColor(layerStyle.getFontFillColor()),
                            PropertyFactory.textHaloWidth(layerStyle.getFontStrokeWidth()),
                            PropertyFactory.textHaloColor(layerStyle.getFontStrokeColor()),
                            PropertyFactory.textFont(layerStyle.getFontBold() == 0
                                    ? new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                            PropertyFactory.textOptional(true),
                            PropertyFactory.textIgnorePlacement(false),
                            PropertyFactory.textOffset(new Float[]{ 0f, getAnnotationSymbolTextOffset(layerStyle) })
                    );
            if (StringUtils.isNotEmpty(showAnnotationKey)) {
                annotationLayer.withProperties(PropertyFactory.textField(Expression.get(showAnnotationKey)));
            } else {
                annotationLayer.withProperties(PropertyFactory.visibility(Property.NONE));
            }
            loadStyle.addLayerAbove(annotationLayer, layerId);
            return layerAnnotationId;
        } else if (gisLayer.getGeometryType() == GisGeometryType.Line) {
            String layerId = getGisLayerOnMapLayerId(gisLayer);
            LineLayer lineLayer = new LineLayer(layerId, sourceId)
                    .withProperties(
                            PropertyFactory.lineWidth(layerStyle.getLineWidth()),
                            PropertyFactory.lineColor(layerStyle.getLineColor()),
                            PropertyFactory.lineOpacity(layerStyle.getLineOpacity()),
                            PropertyFactory.lineCap(Property.LINE_CAP_BUTT)
                    );

            if (layerStyle.getLineType() == 0) {
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_1));
            } else if (layerStyle.getLineType() == 1) {
                //虚线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_2));
            } else if (layerStyle.getLineType() == 2) {
                //点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_3));
            } else if (layerStyle.getLineType() == 3) {
                //虚线-点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_4));
            } else if (layerStyle.getLineType() == 4) {
                //虚线-点-点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_5));
            }

            loadStyle.addLayerAbove(lineLayer, aboveLayerId);

            String layerAnnotationId = GIS_GEO_LINE_ANNOTATION + gisLayerId;
            String showAnnotationKey = layerStyle.getShowAnnotationKey();
            SymbolLayer annotationLayer = new SymbolLayer(layerAnnotationId, sourceId)
                    .withProperties(
                            PropertyFactory.textSize(layerStyle.getFontSize()),
                            PropertyFactory.textColor(layerStyle.getFontFillColor()),
                            PropertyFactory.textHaloWidth(layerStyle.getFontStrokeWidth()),
                            PropertyFactory.textHaloColor(layerStyle.getFontStrokeColor()),
                            PropertyFactory.textFont(layerStyle.getFontBold() == 0 ?
                                    new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                            PropertyFactory.textOptional(true),
                            PropertyFactory.textIgnorePlacement(false)
                    );
            if (StringUtils.isNotEmpty(showAnnotationKey)) {
                annotationLayer.withProperties(PropertyFactory.textField(Expression.get(showAnnotationKey)));
            } else {
                annotationLayer.withProperties(PropertyFactory.visibility(Property.NONE));
            }
            loadStyle.addLayerAbove(annotationLayer, layerId);

            return layerAnnotationId;
        } else if (gisLayer.getGeometryType() == GisGeometryType.Polygon) {
            String layerFillId = getGisLayerOnMapLayerId(gisLayer);
            FillLayer fillLayer = new FillLayer(layerFillId, sourceId);

            if (layerStyle.getFillType() == 0) {
                fillLayer.withProperties(
                                PropertyFactory.fillColor(layerStyle.getFillColor()),
                                PropertyFactory.fillOpacity(layerStyle.getFillOpacity()));
            } else {
                String polygonImageName = GIS_POLYGON_IMAGE_NAME + gisLayer.getId();
                addPolygonImage(polygonImageName, gisLayer);
                fillLayer.setProperties(
                        PropertyFactory.fillPattern(polygonImageName)
                );

            }
            loadStyle.addLayerAbove(fillLayer, aboveLayerId);

            String layerLineId = GIS_GEO_POLYGON_OUTLINE + gisLayerId;
            LineLayer lineLayer = new LineLayer(layerLineId, sourceId)
                    .withProperties(
                            PropertyFactory.lineWidth(layerStyle.getLineWidth()),
                            PropertyFactory.lineColor(layerStyle.getLineColor()),
                            PropertyFactory.lineOpacity(layerStyle.getLineOpacity())
                    );
            if (layerStyle.getLineType() == 0) {
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_1));
            } else if (layerStyle.getLineType() == 1) {
                //虚线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_2));
            } else if (layerStyle.getLineType() == 2) {
                //点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_3));
            } else if (layerStyle.getLineType() == 3) {
                //虚线-点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_4));
            } else if (layerStyle.getLineType() == 4) {
                //虚线-点-点线
                lineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_5));
            }
            loadStyle.addLayerAbove(lineLayer, layerFillId);

            String layerAnnotationId = GIS_GEO_POLYGON_ANNOTATION + gisLayerId;
            String showAnnotationKey = layerStyle.getShowAnnotationKey();
            SymbolLayer annotationLayer = new SymbolLayer(layerAnnotationId, sourceId)
                    .withProperties(
                            PropertyFactory.textSize(layerStyle.getFontSize()),
                            PropertyFactory.textColor(layerStyle.getFontFillColor()),
                            PropertyFactory.textHaloWidth(layerStyle.getFontStrokeWidth()),
                            PropertyFactory.textHaloColor(layerStyle.getFontStrokeColor()),
                            PropertyFactory.textFont(layerStyle.getFontBold() == 0
                                    ? new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                            PropertyFactory.textOptional(true),
                            PropertyFactory.textIgnorePlacement(false)
                    );
            if (StringUtils.isNotEmpty(showAnnotationKey)) {
                annotationLayer.withProperties(PropertyFactory.textField(Expression.get(showAnnotationKey)));
            } else {
                annotationLayer.withProperties(PropertyFactory.visibility(Property.NONE));
            }
            loadStyle.addLayerAbove(annotationLayer, layerLineId);

            return layerAnnotationId;
        }
        return BASE_ANNOTATION_LAYER;
    }

    private void removeGeometryLayer(GisLayer gisLayer) {
        String gisLayerId = gisLayer.getId();
        String sourceId = GIS_GEOMETRY_SOURCE + gisLayerId;

        if (gisLayer.getGeometryType() == GisGeometryType.Point) {
            String layerPointId = getGisLayerOnMapLayerId(gisLayer);
            loadStyle.removeLayer(layerPointId);
            String iconImageName = GIS_ICON_IMAGE_NAME + gisLayerId;
            loadStyle.removeImage(iconImageName);

            String layerAnnotationId = GIS_GEO_POINT_ANNOTATION + gisLayerId;
            loadStyle.removeLayer(layerAnnotationId);
        } else if (gisLayer.getGeometryType() == GisGeometryType.Line) {
            String layerLineId = getGisLayerOnMapLayerId(gisLayer);
            String layerAnnotationId = GIS_GEO_LINE_ANNOTATION + gisLayerId;

            loadStyle.removeLayer(layerLineId);
            loadStyle.removeLayer(layerAnnotationId);
        } else if (gisLayer.getGeometryType() == GisGeometryType.Polygon) {
            String layerFillId = getGisLayerOnMapLayerId(gisLayer);
            String layerLineId = GIS_GEO_POLYGON_OUTLINE + gisLayerId;
            String layerAnnotationId = GIS_GEO_POLYGON_ANNOTATION + gisLayerId;

            loadStyle.removeLayer(layerFillId);
            loadStyle.removeLayer(layerLineId);
            loadStyle.removeLayer(layerAnnotationId);
        }

        boolean result = loadStyle.removeSource(sourceId);
    }

    private void setGisGeometrySourceData(
            Map<String, LinkedHashMap<String, Feature>> sourceData, boolean animateCamera) {
        if (sourceData != null && sourceData.size() > 0) {
            List<Feature> allFeature = new ArrayList<>();
            for (GisLayer gisLayer : gisLayerList) {
                LinkedHashMap<String, Feature> featureMap = sourceData.get(gisLayer.getId());
                if (featureMap == null) {
                    layerIdToFeaturesMap.put(gisLayer.getId(), new LinkedHashMap<>());
                } else {
                    layerIdToFeaturesMap.put(gisLayer.getId(), featureMap);
                    if (featureMap.size() > 0) {
                        GeoJsonSource jsonSource = layerIdToSourceMap.get(gisLayer.getId());
                        List<Feature> featureList = new ArrayList<>(featureMap.values());
                        jsonSource.setGeoJson(FeatureCollection.fromFeatures(featureList));

                        allFeature.addAll(featureList);
                    }
                }
            }

            if (animateCamera) {
                if (allFeature.size() > 0) {
                    double[] bbox = TurfMeasurement.bbox(FeatureCollection.fromFeatures(allFeature));
                    LatLng latLngLeftBottom = new LatLng(bbox[1], bbox[0]);
                    LatLng latLngRightTop = new LatLng(bbox[3], bbox[2]);
                    mMapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(
                            new LatLngBounds.Builder()
                                    .include(latLngLeftBottom)
                                    .include(latLngRightTop)
                                    .build(), 80));
                }
            }
        }
    }

    //清空所以数据，用于重新加载历史版本或其他操作
    private void clearMapLayerAndGeometryData() {
        //考虑在编辑模式时切换编辑图层
        if (opManager != null) {
            if (opManager.getDrawModel() != DrawType.None) {
                opManager.doCloseOperation();
            }
            opManager.setSelectedEditFeature(null);
        }

        for (int i = 0; i < gisLayerList.size(); i++) {
            GisLayer gisLayer = gisLayerList.get(i);
            removeGeometryLayer(gisLayer);
        }

        gisLayerList.clear();
        layerIdToFeaturesMap.clear();
        invisibleFeatureMap.clear();

        currentOpHistoryId = null;
        currentOpLayer = null;
        getView().notifyShowOperationLayout(GisGeometryType.None);
    }

    private void addIconImage(String iconImageName, GisLayer gisLayer) {
        GisLayerStyle layerStyle = gisLayer.getMyLayerStyle();

        int colorInt = Color.parseColor(layerStyle.getFillColor());
        int color = Color.argb((int)(layerStyle.getFillOpacity() * 255),
                Color.red(colorInt), Color.green(colorInt), Color.blue(colorInt));
        Bitmap bitmap = ImageUtils.makeTintBitmap(
                BitmapFactory.decodeResource(getContext().getResources(),
                        GisLayer.getPointStyleRes(layerStyle.getPointType(), layerStyle.getPointStyle())), color);
        loadStyle.addImage(iconImageName, ImageUtils.scale(bitmap, 100, 100));
    }

    private void addPolygonImage(String iconImageName, GisLayer gisLayer) {
        GisLayerStyle layerStyle = gisLayer.getMyLayerStyle();

        int colorInt = Color.parseColor(layerStyle.getFillColor());
        int color = Color.argb((int)(layerStyle.getFillOpacity() * 255),
                Color.red(colorInt), Color.green(colorInt), Color.blue(colorInt));
        Bitmap bitmap = ImageUtils.makeTintBitmap(
                BitmapFactory.decodeResource(getContext().getResources(),
                        GisLayer.getPolygonStyleRes(layerStyle.getFillType())), color);
        loadStyle.addImage(iconImageName, bitmap);
    }

    private GisLayer getGisLayerById(String layerId) {
        int index = gisLayerList.indexOf(new GisLayer(layerId));
        if (index >= 0) {
            return gisLayerList.get(index);
        }
        return null;
    }

    public void notifyLayerVisible(GisLayer gisLayer, boolean isVisible) {
        GisLayer opGisLayer = getGisLayerById(gisLayer.getId());
        if (opGisLayer == null) {
            return;
        }
        opGisLayer.setLayerVisible(isVisible);
        String visibleFlag = isVisible ? Property.VISIBLE : Property.NONE;

        String[] layerIds = getGisLayerOnMapLayerIds(opGisLayer);
        for (String layerId : layerIds) {
            Layer layer = loadStyle.getLayer(layerId);
            if (layer != null) {
                layer.setProperties(PropertyFactory.visibility(visibleFlag));
            }
        }
    }

    public void notifyLayerStyleChange(GisLayer gisLayer) {
        GisLayer opGisLayer = getGisLayerById(gisLayer.getId());
        if (opGisLayer == null) {
            return;
        }

        GisLayerStyle opLayerStyle = opGisLayer.getMyLayerStyle();
        if (gisLayer.getGeometryType() == GisGeometryType.Point) {
            //更新imageIcon
            String iconImageName = GIS_ICON_IMAGE_NAME + gisLayer.getId();
            addIconImage(iconImageName, opGisLayer);

            String layerId = getGisLayerOnMapLayerId(gisLayer);
            Layer layer = loadStyle.getLayer(layerId);
            if (layer != null) {
                layer.setProperties(
                        PropertyFactory.iconSize(opLayerStyle.getPointSize() / 20f),
                        PropertyFactory.iconOpacity(opLayerStyle.getFillOpacity()));
            }

            String layerAnnotationId = GIS_GEO_POINT_ANNOTATION + opGisLayer.getId();
            Layer annotationLayer = loadStyle.getLayer(layerAnnotationId);
            if (annotationLayer != null) {

                String showAnnotationKey = opLayerStyle.getShowAnnotationKey();
                if (StringUtils.isEmpty(showAnnotationKey)) {
                    showAnnotationKey = "-";
                }
                annotationLayer.setProperties(
                        PropertyFactory.textField(Expression.get(showAnnotationKey)),
                        PropertyFactory.textColor(opLayerStyle.getFontFillColor()),
                        PropertyFactory.textSize(opLayerStyle.getFontSize()),
                        PropertyFactory.textHaloWidth(opLayerStyle.getFontStrokeWidth()),
                        PropertyFactory.textHaloColor(opLayerStyle.getFontStrokeColor()),
                        PropertyFactory.textFont(opLayerStyle.getFontBold() == 0
                                ? new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                        PropertyFactory.visibility(StringUtils.isNotEmpty(showAnnotationKey) ? Property.VISIBLE : Property.NONE),
                        PropertyFactory.textOffset(new Float[]{ 0f, getAnnotationSymbolTextOffset(opLayerStyle) })
                );
            }

        }
        else if (gisLayer.getGeometryType() == GisGeometryType.Line) {
            String layerId = getGisLayerOnMapLayerId(gisLayer);
            Layer layer = loadStyle.getLayer(layerId);
            if (layer != null) {
                layer.setProperties(
                        PropertyFactory.lineWidth(opLayerStyle.getLineWidth()),
                        PropertyFactory.lineColor(opLayerStyle.getLineColor()),
                        PropertyFactory.lineOpacity(opLayerStyle.getLineOpacity())
                );

                if (opLayerStyle.getLineType() == 0) {
                    layer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_1));
                } else if (opLayerStyle.getLineType() == 1) {
                    //虚线
                    layer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_2));
                } else if (opLayerStyle.getLineType() == 2) {
                    //点线
                    layer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_3));
                } else if (opLayerStyle.getLineType() == 3) {
                    //虚线-点线
                    layer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_4));
                } else if (opLayerStyle.getLineType() == 4) {
                    //虚线-点-点线
                    layer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_5));
                }

            }

            String layerAnnotationId = GIS_GEO_LINE_ANNOTATION + opGisLayer.getId();
            Layer annotationLayer = loadStyle.getLayer(layerAnnotationId);
            if (annotationLayer != null) {

                String showAnnotationKey = opLayerStyle.getShowAnnotationKey();
                if (StringUtils.isEmpty(showAnnotationKey)) {
                    showAnnotationKey = "-";
                }
                annotationLayer.setProperties(
                        PropertyFactory.textField(Expression.get(showAnnotationKey)),
                        PropertyFactory.textColor(opLayerStyle.getFontFillColor()),
                        PropertyFactory.textSize(opLayerStyle.getFontSize()),
                        PropertyFactory.textHaloWidth(opLayerStyle.getFontStrokeWidth()),
                        PropertyFactory.textHaloColor(opLayerStyle.getFontStrokeColor()),
                        PropertyFactory.textFont(opLayerStyle.getFontBold() == 0
                                ? new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                        PropertyFactory.visibility(StringUtils.isNotEmpty(showAnnotationKey) ? Property.VISIBLE : Property.NONE)
                );
            }

        }
        else if (gisLayer.getGeometryType() == GisGeometryType.Polygon) {
            String layerFillId = getGisLayerOnMapLayerId(gisLayer);
            Layer fillLayer = loadStyle.getLayer(layerFillId);
            if (fillLayer != null) {
                if (opLayerStyle.getFillType() == 0) {
                    fillLayer.setProperties(
                            PropertyFactory.fillColor(opLayerStyle.getFillColor()),
                            PropertyFactory.fillOpacity(opLayerStyle.getFillOpacity()),
                            PropertyFactory.fillPattern((String) null)
                    );
                } else {
                    String polygonImageName = GIS_POLYGON_IMAGE_NAME + gisLayer.getId();
                    addPolygonImage(polygonImageName, gisLayer);
                    fillLayer.setProperties(
                            PropertyFactory.fillPattern(polygonImageName)
                    );

                }
            }

            String layerOutLineId = GIS_GEO_POLYGON_OUTLINE + opGisLayer.getId();
            Layer outlineLayer = loadStyle.getLayer(layerOutLineId);
            if (outlineLayer != null) {
                outlineLayer.setProperties(
                        PropertyFactory.lineWidth(opLayerStyle.getLineWidth()),
                        PropertyFactory.lineColor(opLayerStyle.getLineColor()),
                        PropertyFactory.lineOpacity(opLayerStyle.getLineOpacity())
                );
                if (opLayerStyle.getLineType() == 0) {
                    outlineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_1));
                } else if (opLayerStyle.getLineType() == 1) {
                    //虚线
                    outlineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_2));
                } else if (opLayerStyle.getLineType() == 2) {
                    //点线
                    outlineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_3));
                } else if (opLayerStyle.getLineType() == 3) {
                    //虚线-点线
                    outlineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_4));
                } else if (opLayerStyle.getLineType() == 4) {
                    //虚线-点-点线
                    outlineLayer.setProperties(PropertyFactory.lineDasharray(GIS_LAYER_STYLE_LINE_TYPE_5));
                }
            }

            String layerAnnotationId = GIS_GEO_POLYGON_ANNOTATION + opGisLayer.getId();
            Layer annotationLayer = loadStyle.getLayer(layerAnnotationId);
            if (annotationLayer != null) {

                String showAnnotationKey = opLayerStyle.getShowAnnotationKey();
                if (StringUtils.isEmpty(showAnnotationKey)) {
                    showAnnotationKey = "-";
                }
                annotationLayer.setProperties(
                        PropertyFactory.textField(Expression.get(showAnnotationKey)),
                        PropertyFactory.textColor(opLayerStyle.getFontFillColor()),
                        PropertyFactory.textSize(opLayerStyle.getFontSize()),
                        PropertyFactory.textHaloWidth(opLayerStyle.getFontStrokeWidth()),
                        PropertyFactory.textHaloColor(opLayerStyle.getFontStrokeColor()),
                        PropertyFactory.textFont(opLayerStyle.getFontBold() == 0 ? new String[]{ "Open Sans Regular" } : new String[]{ "Open Sans Bold" }),
                        PropertyFactory.visibility(StringUtils.isNotEmpty(showAnnotationKey) ? Property.VISIBLE : Property.NONE)
                );
            }
        }
        localGeoManger.insertOrReplaceLayerStyle(opLayerStyle, true);
        editLayerStyle = true;
    }

    private float getAnnotationSymbolTextOffset(GisLayerStyle layerStyle) {
        return ((layerStyle.getPointSize() * 13f / 200f) + (layerStyle.getFontSize() / 12f) * 0.5f);
    }

    public void notifyLayerSortChange(GisLayer moveLayer, int fromPosition, int toPosition) {

        if (0 <= fromPosition && fromPosition < gisLayerList.size()
                && 0 <= toPosition && toPosition < gisLayerList.size()) {
            GisLayer mGisLayer = gisLayerList.remove(fromPosition);
            gisLayerList.add(toPosition, mGisLayer);

            //寻找添加到哪个图层上面
            GisLayer aboveLayer = null;
            if (toPosition + 1 < gisLayerList.size()) {
                aboveLayer = gisLayerList.get(toPosition + 1);
            }

            //需要移动的图层
            List<Layer> moveLayerList = new ArrayList<>();
            String[] moveLayerIds = getGisLayerOnMapLayerIds(mGisLayer);
            for (String layerId : moveLayerIds) {
                Layer layer = loadStyle.getLayer(layerId);
                if (layer != null) {
                    moveLayerList.add(layer);
                    boolean result = loadStyle.removeLayer(layer);
                }
            }

            String aboveLayerId = null;
            if (aboveLayer != null) {
                //移动到改图层上面
                String[] aboveLayerIds = getGisLayerOnMapLayerIds(aboveLayer);
                aboveLayerId = aboveLayerIds[aboveLayerIds.length - 1];
            } else {
                //移动到最底部
                aboveLayerId = BASE_ANNOTATION_LAYER;
            }


            if (StringUtils.isNotEmpty(aboveLayerId)) {

                for (int i = 0; i < moveLayerList.size(); i++) {
                    Layer layer = moveLayerList.get(i);
                    loadStyle.addLayerAbove(layer, aboveLayerId);
                    aboveLayerId = layer.getId();
                }
            } else {
                for (Layer layer : moveLayerList) {
                    loadStyle.addLayer(layer);
                }
            }

            //重新设置排序号
            for (int i = 0; i < gisLayerList.size(); i++) {
                gisLayerList.get(i).setSort(i);
            }

            saveLocalDBData(GisMapGeoManger.OP_SORT_LAYER);
        }

    }

    public void notifySelectedLayer(String layerId) {
        //考虑在编辑模式时切换编辑图层
        if (opManager != null) {
            if (opManager.getDrawModel() != DrawType.None) {
                opManager.doCloseOperation();
            }
            opManager.setSelectedEditFeature(null);
        }

        //清除不可见列表
        setFeatureSourceVisible(currentOpLayer, true);
        if (StringUtils.isNotEmpty(layerId)) {

            currentOpLayer = getGisLayerById(layerId);
            getView().notifyShowOperationLayout(currentOpLayer.getGeometryType());
            GeometryOpManager.OpGeometryType geoType = GeometryOpManager.OpGeometryType.Polygon;
            if (currentOpLayer.getGeometryType() == GisGeometryType.Point) {
                geoType = GeometryOpManager.OpGeometryType.Point;
            } else if (currentOpLayer.getGeometryType() == GisGeometryType.Line) {
                geoType = GeometryOpManager.OpGeometryType.Line;
            }
            opManager.setGeometryType(geoType);
        } else {
            currentOpLayer = null;
            getView().notifyShowOperationLayout(GisGeometryType.None);
        }

        if (currentOpLayer != null && currentOpLayer.getType() == GisGeometryType.Point.getType()) {
            GisLayerStyle layerStyle = currentOpLayer.getMyLayerStyle();
            Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
                    GisLayer.getPointStyleRes(layerStyle.getPointType(), 0));
            opManager.updateSelectedEditPointLayerStyle(
                    ImageUtils.scale(bitmap, 100, 100), layerStyle.getPointSize() / 20f);
        } else {
            opManager.updateSelectedEditPointLayerStyle(null, 0.5f);
        }
        if (layerManagerFragment != null) {
            layerManagerFragment.setSelectedLayer(currentOpLayer);
        }
    }

    public void notifyRemoveLayer(String layerId) {
        GisLayer targetLayer = getGisLayerById(layerId);
        if (targetLayer != null) {
            gisLayerList.remove(targetLayer);
            removeGeometryLayer(targetLayer);

            layerIdToFeaturesMap.remove(layerId);
            invisibleFeatureMap.remove(layerId);

            //如果删除的是当前操作的图层，则退出编辑模式
            if (currentOpLayer != null && currentOpLayer.getId().equals(layerId)) {
                if (opManager != null) {
                    if (opManager.getDrawModel() != DrawType.None) {
                        opManager.doCloseOperation();
                    }
                    opManager.setSelectedEditFeature(null);
                }
                currentOpLayer = null;
                getView().notifyShowOperationLayout(GisGeometryType.None);
            }

            //重新设置排序号
            for (int i = 0; i < gisLayerList.size(); i++) {
                gisLayerList.get(i).setSort(i);
            }

            saveLocalDBData(GisMapGeoManger.OP_REMOVE_LAYER);
        }
    }

    public void addGisLayer(GisLayer gisLayer) {
        addGisLayer(gisLayer, true);
    }

    public void addGisLayer(GisLayer gisLayer, boolean saveLocalDB) {
        GisLayer firstLayer = gisLayerList.size() > 0 ? gisLayerList.get(0) : null;
        gisLayerList.add(0, gisLayer);
        layerIdToFeaturesMap.put(gisLayer.getId(), new LinkedHashMap<>());

        //更新序号
        for (int i = 0; i < gisLayerList.size(); i++) {
            GisLayer layer = gisLayerList.get(i);
            layer.setSort(i);
        }

        String aboveLayerId = firstLayer == null
                ? BASE_ANNOTATION_LAYER : getGisLayerOnMapLayerId(firstLayer);
        addGeometryLayer(gisLayer, aboveLayerId);
        if (layerManagerFragment != null) {
            layerManagerFragment.initData(gisLayerList);
        }

        if (saveLocalDB) {
            saveLocalDBData(GisMapGeoManger.OP_ADD_LAYER);
        }
        localGeoManger.insertOrReplaceLayerStyle(gisLayer.getMyLayerStyle(), true);
    }

    public boolean showLayerManagerDialog() {
        if (layerManagerFragment == null) {
            layerManagerFragment = new GisLayerManagerFragment();
            Bundle bundle = new Bundle();
            if (currentOpLayer != null) {
                bundle.putString("selectedLayerId", currentOpLayer.getId());
            }
            bundle.putString("projectId", gisProjectId);
            layerManagerFragment.setArguments(bundle);
        }

        if (isShowingLayerManager) {
            hideLayerManagerFragment();
        } else {
            layerManagerFragment.initData(gisLayerList);
            getView().replaceFragment(
                    R.id.fl_layer_manager_box, layerManagerFragment);
            isShowingLayerManager = true;
        }
        return isShowingLayerManager;
    }

    private void hideLayerManagerFragment() {
        if (layerManagerFragment != null) {
            getView().removeFragment(layerManagerFragment);
        }
        isShowingLayerManager = false;
    }


    public boolean showOpHistoryDialog() {
        if (historyFragment == null) {
            historyFragment = new GisOpHistoryFragment();
        }
        if (isShowingLayerHistory) {
            hideOpHistoryDialog();
        } else {
            if (historyFragment.getGisMapGeoManger() == null) {
                historyFragment.setProjectData(localGeoManger, gisProjectId, currentOpHistoryId);
            }
            getView().replaceFragment(
                    R.id.fl_layer_history_box, historyFragment);
            isShowingLayerHistory = true;
        }
        return isShowingLayerHistory;
    }

    private void hideOpHistoryDialog() {
        if (historyFragment != null) {
            getView().removeFragment(historyFragment);
            historyFragment = null;
        }
        isShowingLayerHistory = false;
    }

    public void showGeometryListDialog(GisLayer gisLayer) {
        if (gisLayer != null) {
            List<Feature> features = new ArrayList<>();
            LinkedHashMap<String, Feature> featureMap = layerIdToFeaturesMap.get(gisLayer.getId());
            if (featureMap != null) {
                Iterator<Map.Entry<String, Feature>> iterator = featureMap.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, Feature> entry = iterator.next();
                    features.add(entry.getValue());
                }
            }
            geometryListFragment = GisLayerGeometryListFragment.getInstance(
                    gisLayer.getId(), gisLayer.getFieldList(), features, true);
            geometryListFragment.setClickListener(new GisLayerGeometryListFragment.OnClickListener() {

                @Override
                public void onClose() {
                    hideGeometryListFragment();
                }

                @Override
                public void onClickFeature(String layerId, String featureId) {

                }

                @Override
                public void onLocateFeature(String layerId, String featureId) {
                    if (layerIdToFeaturesMap.containsKey(layerId)) {
                        Map<String, Feature> map = layerIdToFeaturesMap.get(layerId);
                        if (map.containsKey(featureId)) {
                            Feature feature = map.get(featureId);
                            mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
                                    mMapboxMap.getCameraForGeometry(feature.geometry())));
                        }
                    }
                }

                @Override
                public void onDeleteFeature(String layerId, String featureId) {
                    if (layerIdToFeaturesMap.containsKey(layerId)) {
                        Map<String, Feature> map = layerIdToFeaturesMap.get(layerId);
                        if (map.containsKey(featureId)) {
                            if (opManager.getSelectedEditFeature() != null
                                    && opManager.getSelectedEditFeatureId().equals(featureId)) {
                                opManager.setSelectedEditFeature(null);
                            }
                            map.remove(featureId);

                            saveLocalDBData(GisMapGeoManger.OP_REMOVE_GEOMETRY);

                            notifyLayerSourceChange(getGisLayerById(layerId));
                        }
                    }
                }
            });
            getView().replaceFragment(
                    R.id.fl_layer_geometry_list_box, geometryListFragment);
            isShowingGeometryList = true;
        }
    }

    private void hideGeometryListFragment() {
        if (geometryListFragment != null) {
            getView().removeFragment(geometryListFragment);
            geometryListFragment = null;
        }
        isShowingGeometryList = false;
    }

    //加载打开项目时的数据
    public void chooseLoadOpenProjectData() {
        clearMapLayerAndGeometryData();

        if (isLocal) {
            loadProjectVersionData(openVersionId, false);
        } else {
            loadNetProjectVersionData(gisProjectId, false);
        }

        if (layerManagerFragment != null) {
            layerManagerFragment.setSelectedLayer(null);
        }
        if (historyFragment != null) {
            historyFragment.notifyChooseHistoryItem("");
        }
    }

    //加载历史数据
    public void chooseLoadOpHistory(String opHistoryId) {
        clearMapLayerAndGeometryData();

        loadOpHistoryData(opHistoryId, false);
        if (layerManagerFragment != null) {
            layerManagerFragment.setSelectedLayer(null);
        }
        if (historyFragment != null) {
            historyFragment.notifyChooseHistoryItem(opHistoryId);
        }

    }


    public boolean onMapClick(LatLng point) {
        if (measureManager.getMeasureType() != MeasureManager.MeasureType.None) {
            measureManager.onMeasureClickMap(point);
            return true;
        }
        if (currentOpLayer != null) {
            if (opManager.getDrawModel() == DrawType.None) {
                //查询图形
                doQueryFeature(currentOpLayer, point);
            } else {
                opManager.dealMapClick(point);
            }
            return true;
        } else if (opManager.getDrawModel() == DrawType.None) {
            doQueryFeature(point);
        }
        return false;
    }

    private void doQueryFeature(LatLng latLng) {
        if (latLng == null) {
            return;
        }
        GisLayer queryLayer = null;
        Feature queryFeature = null;
        Iterator<GisLayer> iterator = gisLayerList.iterator();
        while (iterator.hasNext()) {
            GisLayer gisLayer = iterator.next();
            Feature feature = queryFeatureByMapPoint(gisLayer, latLng);
            if (feature != null) {
                queryLayer = gisLayer;
                queryFeature = feature;
                break;
            }
        }
        if (queryFeature != null) {
            notifySelectedLayer(queryLayer.getId());

            String featureId = queryFeature.getStringProperty(FEATURE_ID);
            setFeatureSourceVisible(currentOpLayer, featureId, false);
            opManager.setSelectedEditFeature(queryFeature);
        } else {
            if (opManager.getSelectedEditFeature() != null) {
                setFeatureSourceVisible(currentOpLayer, opManager.getSelectedEditFeatureId(), true);
            }
            opManager.setSelectedEditFeature(null);

        }
    }

    private void doQueryFeature(GisLayer gisLayer, LatLng latLng) {
        if (gisLayer == null || latLng == null) {
            return;
        }
        Feature feature = queryFeatureByMapPoint(gisLayer, latLng);
        if (feature != null) {
            if (opManager.getSelectedEditFeature() != null) {
                setFeatureSourceVisible(currentOpLayer, opManager.getSelectedEditFeatureId(), true);
            }

            String featureId = feature.getStringProperty(FEATURE_ID);
            setFeatureSourceVisible(currentOpLayer, featureId, false);
            opManager.setSelectedEditFeature(feature);
        } else {
            if (opManager.getSelectedEditFeature() != null) {
                setFeatureSourceVisible(currentOpLayer, opManager.getSelectedEditFeatureId(), true);
            }
            opManager.setSelectedEditFeature(null);

        }
    }


    private Feature queryFeatureByMapPoint(GisLayer gisLayer, LatLng latLng) {
        List<Feature> features = queryRenderedFeatures(gisLayer, latLng);
        if (features.size() > 0) {
            String featureId = null;
            for (Feature feature : features) {
                boolean isInside = false;
                //queryRenderedFeatures该函数没有考虑孔洞问题，因此调用TurfJoins.inside方法判断
                if (feature.geometry() instanceof MultiPolygon) {
                    isInside = TurfJoins.inside(Point.fromLngLat(
                            latLng.getLongitude(), latLng.getLatitude()),
                            (MultiPolygon) feature.geometry());
                } else if (feature.geometry() instanceof Polygon) {
                    isInside = TurfJoins.inside(Point.fromLngLat(
                            latLng.getLongitude(), latLng.getLatitude()),
                            (Polygon) feature.geometry());
                } else if (feature.geometry() instanceof Point
                        || feature.geometry() instanceof MultiPoint
                        || feature.geometry() instanceof LineString
                        || feature.geometry() instanceof MultiLineString) {
                    isInside = true;
                }

                if (isInside && feature.hasProperty(FEATURE_ID)) {
                    featureId = feature.getStringProperty(FEATURE_ID);
                    break;
                }
            }
            if (featureId != null
                    && layerIdToFeaturesMap.containsKey(gisLayer.getId())
                    && layerIdToFeaturesMap.get(gisLayer.getId()) != null) {
                //从idToFeatureMap中查找出该对象
                Feature feature = layerIdToFeaturesMap
                        .get(gisLayer.getId()).get(featureId);
                return feature;
            }
        }
        return null;
    }

    private List<Feature> queryRenderedFeatures(GisLayer gisLayer, LatLng latLng) {
        String queryLayerId = getGisLayerOnMapLayerId(gisLayer);
        if (gisLayer.getGeometryType() == GisGeometryType.Polygon) {
            //多边形直接用点查询
            PointF pointF = mMapboxMap.getProjection().toScreenLocation(latLng);
            return mMapboxMap.queryRenderedFeatures(pointF, queryLayerId);
        } else {
            //1°在经度上大概111Km

            double zoom = mMapboxMap.getCameraPosition().zoom;
            double offset = gisLayer.getGeometryType() == GisGeometryType.Line
                    ? 0.01 * zoom : 0.01 * zoom;
            double longitude = latLng.getLongitude();
            double latitude = latLng.getLatitude();

            //点和线比较细，扩大点击区域
            PointF pointLeftBottom = mMapboxMap.getProjection().toScreenLocation(
                    new LatLng(latitude - offset, longitude - offset));
            PointF pointRightTop = mMapboxMap.getProjection().toScreenLocation(
                    new LatLng(latitude + offset, longitude + offset));

            RectF rectF = new RectF(pointLeftBottom.x, pointRightTop.y, pointRightTop.x, pointLeftBottom.y);
            return mMapboxMap.queryRenderedFeatures(rectF, queryLayerId);
        }
    }


    public void clickDrawType(DrawType drawType) {
        if ((drawType == DrawType.Huizhi || drawType == DrawType.Shanchu)
                && opManager.getSelectedEditFeature() != null) {
            //绘制时将选中的图像变为可见
            setFeatureSourceVisible(currentOpLayer, opManager.getSelectedEditFeatureId(), true);
        }
        opManager.clickTopicOp(drawType);
        if (opManager.getDrawModel() != DrawType.None && currentOpLayer != null) {
            if (currentOpLayer.getType() == GisGeometryType.Point.getType()) {
                GisLayerStyle layerStyle = currentOpLayer.getMyLayerStyle();
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
                        GisLayer.getPointStyleRes(layerStyle.getPointType(), 0));
                opManager.updateOpEditPointLayerStyle(ImageUtils.scale(bitmap, 100, 100),
                        layerStyle.getPointSize() / 20f);
            } else {
                opManager.updateOpEditPointLayerStyle(null, 0.5f);
            }
        }
    }


    private void setFeatureSourceVisible(GisLayer gisLayer, boolean visible) {
        if (gisLayer != null) {
            String layerId = gisLayer.getId();
            Set<String> featureIdSet = invisibleFeatureMap.get(layerId);
            if (visible) {
                if (featureIdSet != null) {
                    featureIdSet.clear();
                }
            } else {
                if (featureIdSet == null) {
                    featureIdSet = new HashSet<>();
                    invisibleFeatureMap.put(layerId, featureIdSet);
                }
                featureIdSet.addAll(layerIdToFeaturesMap.get(layerId).keySet());
            }
            notifyLayerSourceChange(gisLayer);
        }
    }

    private void setFeatureSourceVisible(GisLayer gisLayer, String featureId, boolean visible) {
        if (gisLayer != null && StringUtils.isNotEmpty(featureId)) {
            String layerId = gisLayer.getId();
            Set<String> featureIdSet = invisibleFeatureMap.get(layerId);
            if (visible) {
                if (featureIdSet != null) {
                    featureIdSet.remove(featureId);
                }
            } else {
                if (featureIdSet != null) {
                    featureIdSet.add(featureId);
                } else {
                    featureIdSet = new HashSet<>();
                    featureIdSet.add(featureId);
                    invisibleFeatureMap.put(layerId, featureIdSet);
                }
            }

            notifyLayerSourceChange(gisLayer);
        }
    }


    private void notifyLayerSourceChange(GisLayer gisLayer) {
        String layerId = gisLayer.getId();
        GeoJsonSource jsonSource = layerIdToSourceMap.get(layerId);
        Map<String, Feature> sourceFeatureMap = layerIdToFeaturesMap.get(layerId);
        Set<String> invisibleFeatureSet = invisibleFeatureMap.get(layerId);

        if (sourceFeatureMap == null) {
            return;
        }

        if (invisibleFeatureSet != null && invisibleFeatureSet.size() > 0) {
            List<Feature> features = new ArrayList<>();
            Iterator<Map.Entry<String, Feature>> iterator = sourceFeatureMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Feature> entry = iterator.next();
                if (!invisibleFeatureSet.contains(entry.getKey())) {
                    features.add(entry.getValue());
                }
            }
            jsonSource.setGeoJson(FeatureCollection.fromFeatures(features));
        } else {
            jsonSource.setGeoJson(FeatureCollection.fromFeatures(new ArrayList<>(sourceFeatureMap.values())));
        }
    }


    public void clickSaveOperation() {
        if (opManager != null) {
            opManager.clickSaveOperation();
        }
    }

    public void clickUndoOperation() {
        if (opManager != null) {
            opManager.clickUndoOperation();
        }
    }

    public void clickRedoOperation() {
        if (opManager != null) {
            opManager.clickRedoOperation();
        }
    }

    public void clickClearOperation() {
        if (opManager != null) {
            opManager.clickClearOperation();
        }
    }

    public void clickCloseOperation() {
        if (opManager != null) {
            opManager.doCloseOperation();
        }
    }

    public void clickSubmitOperation() {
        if (opManager != null) {

            DrawType drawType = opManager.getDrawModel();
            if (drawType == DrawType.Bianjie || drawType == DrawType.Shanchu) {
                //这几个都没有设置完成按钮，点击提交自动帮保存
                opManager.clickSaveOperation();
            }


            GeoSubmitResult submitResult = opManager.doSubmitOperation();
            Map<String, Feature> sourceFeatureMap = layerIdToFeaturesMap.get(currentOpLayer.getId());
            Set<String> removeEditIds = submitResult.getRemoveEditIds();

            if (drawType == DrawType.Huizhi) {
                for (Feature feature : submitResult.getResultFeatures()) {
                    String featureId = UuidUtils.generateId();
                    feature.addStringProperty(FEATURE_ID, featureId);

                    //添加居然有默认值的属性
                    if (currentOpLayer.getFieldList() != null) {
                        for (GisField field : currentOpLayer.getFieldList()) {
                            if (StringUtils.isNotEmpty(field.getColumnDefault())) {
                                feature.addStringProperty(field.getId(), field.getColumnDefault());
                            }
                        }
                    }

                    sourceFeatureMap.put(featureId, feature);
                }
            } else if (drawType == DrawType.Bianjie) {
                for (Feature feature : submitResult.getResultFeatures()) {
                    String featureId = feature.getStringProperty(FEATURE_ID);
                    if (featureId == null) {
                        featureId = UuidUtils.generateId();
                        feature.addStringProperty(FEATURE_ID, featureId);
                    }
                    sourceFeatureMap.put(featureId, feature);
                }
            } else if (drawType == DrawType.Qiege || drawType == DrawType.Wakong) {
                String currentEditFeatureId = submitResult.getSelectedEditFeatureId();
                if (sourceFeatureMap != null && sourceFeatureMap.size() > 0) {
                    sourceFeatureMap.remove(currentEditFeatureId);
                }

                List<Feature> features = new ArrayList<>();
                int maxAreaIndex = 0;
                double maxArea = 0;
                JsonObject property = submitResult.getEditSourceFeature().properties();
                String editFeatureId = property.remove(FEATURE_ID).getAsString();
                for (int i = 0; i < submitResult.getResultFeatures().size(); i++) {
                    Feature resultFeature = submitResult.getResultFeatures().get(i);
                    Feature feature = Feature.fromGeometry(resultFeature.geometry(), property.deepCopy());
                    double area = TurfMeasurement.area(feature);
                    if (area > maxArea) {
                        maxAreaIndex = i;
                    }
                    features.add(feature);
                }
                //最大面积图形继承原始的图形id
                features.get(maxAreaIndex).addStringProperty(FEATURE_ID, editFeatureId);

                for (Feature feature : features) {
                    String featureId = feature.getStringProperty(FEATURE_ID);
                    if (featureId == null) {
                        featureId = UuidUtils.generateId();
                        feature.addStringProperty("id", featureId);
                    }
                    sourceFeatureMap.put(featureId, feature);
                }
            } else if (drawType == DrawType.Hebing) {
                List<Feature> features = new ArrayList<>();
                JsonObject property = submitResult.getEditSourceFeature().properties();
                String editFeatureId = property.remove(FEATURE_ID).getAsString();
                for (int i = 0; i < submitResult.getResultFeatures().size(); i++) {
                    Feature resultFeature = submitResult.getResultFeatures().get(i);
                    Feature feature = Feature.fromGeometry(resultFeature.geometry(), property.deepCopy());
                    features.add(feature);
                }
                features.get(0).addStringProperty(FEATURE_ID, editFeatureId);
                for (Feature feature : features) {
                    String featureId = feature.getStringProperty(FEATURE_ID);
                    if (featureId == null) {
                        featureId = UuidUtils.generateId();
                        feature.addStringProperty("id", featureId);
                    }
                    sourceFeatureMap.put(featureId, feature);
                }
            } else if (drawType == DrawType.Shanchu) {

            }

            if (sourceFeatureMap != null && sourceFeatureMap.size() > 0 && !removeEditIds.isEmpty()) {
                for (String id : removeEditIds) {
                    sourceFeatureMap.remove(id);
                }
            }
            removeEditIds.clear();

            setFeatureSourceVisible(currentOpLayer, true);
            notifyLayerSourceChange(currentOpLayer);

            opManager.doCloseOperation();
            opManager.setSelectedEditFeature(null);


            saveLocalDBData(getOperationFlagByDrawType(drawType));
        }
    }

    private String getOperationFlagByDrawType(DrawType drawType) {
        if (drawType == DrawType.Huizhi) {
            return GisMapGeoManger.OP_ADD_GEOMETRY;
        } else if (drawType == DrawType.Bianjie) {
            return GisMapGeoManger.OP_BIANJIE_GEOMETRY;
        } else if (drawType == DrawType.Qiege) {
            return GisMapGeoManger.OP_QIEGE_GEOMETRY;
        } else if (drawType == DrawType.Wakong) {
            return GisMapGeoManger.OP_WAKONG_GEOMETRY;
        } else if (drawType == DrawType.Hebing) {
            return GisMapGeoManger.OP_HEBING_GEOMETRY;
        } else if (drawType == DrawType.Shanchu) {
            return GisMapGeoManger.OP_REMOVE_GEOMETRY;
        }
        return null;
    }

    private void saveLocalDBData(@GisMapGeoManger.OperationFlag String operationFlag) {
        //更新到本地数据库
        String opHistoryId = localGeoManger.saveHistory(currentOpHistoryId, gisProjectId,
                operationFlag, gisLayerList, layerIdToFeaturesMap);
        if (StringUtils.isNotEmpty(opHistoryId)) {
            currentOpHistoryId = opHistoryId;
            if (historyFragment != null) {
                historyFragment.queryDataList(currentOpHistoryId);
            }
        }
    }

    public void clickConform() {
        if (hadEdit()) {
            if (isLocal) {
                if (localGeoManger != null) {
                    boolean result = localGeoManger.submitSaveVersion(
                            gisProjectId, currentOpHistoryId);
                    if (result) {
                        getView().submitSuccess();
                    } else {
                        getView().showToast("保存失败");
                    }
                }
            } else {

            }
        } else {
            getView().showToast("没有需要提交的内容");
        }
    }


    public boolean entryMeasureModel() {
        if (measureManager.getMeasureType() != MeasureManager.MeasureType.None) {
            measureManager.setMeasureType(MeasureManager.MeasureType.None);
            return false;
        } else {
            measureManager.setMeasureType(MeasureManager.MeasureType.LandAnalysis);
            return true;
        }
    }

    public void closeMeasureModel() {
        measureManager.clearMeasureLayer();
    }

    public void clickClearCurrentMeasure() {
        measureManager.clearCurrentMeasureData();
    }

    public void clickMeasureUnit(Context context) {
        final String[] items;
        if (measureManager.getMeasureType() == MeasureManager.MeasureType.MeasureDistance) {
            items = new String[]{ "米", "千米" };
        } else {
            items = new String[]{ "亩", "公顷" };
        }
        new AlertDialog.Builder(context)
                .setItems(items, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        if (measureManager.getMeasureType() == MeasureManager.MeasureType.MeasureDistance) {

                            if (i == 0) {
                                measureManager.setDistanceUnit(MeasureManager.DistanceUnit.METERS);
                            } else {
                                measureManager.setDistanceUnit(MeasureManager.DistanceUnit.KILOMETERS);
                            }
                        } else {
                            if (i == 0) {
                                measureManager.setAreaUnit(MeasureManager.AreaUnit.MU);
                            } else {
                                measureManager.setAreaUnit(MeasureManager.AreaUnit.HECTARE);
                            }

                        }
                    }
                }).create().show();
    }

    public void clickUndoMeasure() {
        measureManager.undoMeasure();
    }

    public void saveCurrentMeasure() {
        measureManager.saveCurrentMeasure();
    }

    //撤销
    public void doUndoGisOpHistory() {
        if (StringUtils.isNotEmpty(currentOpHistoryId)) {
            String preHistoryId = localGeoManger.queryPreviousOpHistoryId(
                    gisProjectId, currentOpHistoryId);
            if (StringUtils.isNotEmpty(preHistoryId)) {
                chooseLoadOpHistory(preHistoryId);
            } else {
                //没有历史id说明已经到顶，即加载打开项目时的状态
                chooseLoadOpenProjectData();
            }
            if (isShowingLayerHistory && historyFragment != null) {
                historyFragment.notifyChooseHistoryItem(preHistoryId);
            }
        } else {
            getView().showToast("没有可撤销的记录");
        }
    }

    //重做
    public void doRedoGisOpHistory() {
        String nextHistoryId = localGeoManger.queryNextOpHistoryId(gisProjectId, currentOpHistoryId);
        if (StringUtils.isNotEmpty(nextHistoryId)) {
            chooseLoadOpHistory(nextHistoryId);
            if (isShowingLayerHistory && historyFragment != null) {
                historyFragment.notifyChooseHistoryItem(nextHistoryId);
            }
        } else {
            getView().showToast("没有可重做的记录");
        }
    }


    /**
     * 获取图层在添加到Mapbox中的图层id
     * 注意Polygon是由两个图层组成，该方法只返回FillLayer图层id
     */
    private String getGisLayerOnMapLayerId(GisLayer gisLayer) {
        if (gisLayer.getGeometryType() == GisGeometryType.Point) {
            return GIS_GEO_POINT + gisLayer.getId();
        } else if (gisLayer.getGeometryType() == GisGeometryType.Line) {
            return GIS_GEO_LINE + gisLayer.getId();
        } else {
            return GIS_GEO_POLYGON_FILL + gisLayer.getId();
        }
    }

    private String[] getGisLayerOnMapLayerIds(GisLayer gisLayer) {
        if (gisLayer.getGeometryType() == GisGeometryType.Point) {
            return new String[]{ GIS_GEO_POINT + gisLayer.getId(),
                    GIS_GEO_POINT_ANNOTATION + gisLayer.getId() };
        } else if (gisLayer.getGeometryType() == GisGeometryType.Line) {
            return new String[]{ GIS_GEO_LINE + gisLayer.getId(),
                    GIS_GEO_LINE_ANNOTATION + gisLayer.getId() };
        } else {
            return new String[]{
                    GIS_GEO_POLYGON_FILL + gisLayer.getId(),
                    GIS_GEO_POLYGON_OUTLINE + gisLayer.getId(),
                    GIS_GEO_POLYGON_ANNOTATION + gisLayer.getId() };
        }
    }

    private void animateCameraToFeature(Feature feature) {
        if (mMapboxMap != null) {
            mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
                    mMapboxMap.getCameraForGeometry(feature.geometry())));
        }
    }

    public void onDestroy() {
        if (localGeoManger != null) {
            localGeoManger.closeDb();
        }
    }

}